﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml.Linq;
using mscook.core.utils;
using Newtonsoft.Json;

namespace mscook.core.services
{
    public class ArticleTemplateFactory : mscook.core.services.IArticleTemplateFactory
    {
        public static readonly string ARTICLE_COMPONENT_DIRECTORY = "ArticleComponent";
        public static readonly string ARTICLE_TEMPLATE_DIRECTORY = "ArticleTemplate";
        public static readonly string ARTICLE_EDITABLE_CONTROL_UNIT_DIRECTORY = "EditableControlUnit";
        public static readonly string ARTICLE_CONTROL_UNIT_DIRECTORY = "ControlUnit";
        public static readonly string ARTICLE_PUBLISH = "ArticlePublish";
        private static readonly XNamespace ns = ImageSettingFactory.ns;
        //private Dictionary<ArticleKey, IList<ArticleComponent>> articleDictionary = new Dictionary<ArticleKey, IList<ArticleComponent>>();
        //2013-10-23 basilwang 应该启用定时检查机制，如果ArticleComponent内的组件内容变化了，应该重新加载该字典表
       //TODO 应该补一个测试用例
        private Dictionary<ArticleComponent, string> componentDictionary = new Dictionary<ArticleComponent, string>();
        private Dictionary<ArticleControlUnit, string> controlUnitDictionary = new Dictionary<ArticleControlUnit, string>();
        private Dictionary<ArticleControlUnit, string> editableControlUnitDictionary = new Dictionary<ArticleControlUnit, string>();
        //private Dictionary<ArticleKey, string> publishDictionary = new Dictionary<ArticleKey, string>();
        private Dictionary<ArticleKey, ArticlePublishDetail> articlePublishDetailDictionary = new Dictionary<ArticleKey, ArticlePublishDetail>();
        public ArticleTemplateFactory()
        {
            this.articleComponentDirectory = GetArticleComponentDirectory();
            this.articleTemplateDirectory = GetArticleTemplateDirectory();
            this.articleControlUnitDirectory = GetArticleControlUnitDirectory();
            this.articlePublishDirectory = GetArticlePublishDirectory();
            this.articleEditableControlUnitDirectory = GetArticleEditableControlUnitDirectory();
            LoadComponents();
            LoadControlUnits();
            LoadEditableControlUnits();
            LoadArticlePublishDetails();
            
        }

        /// <summary>
        ///  根据Component{name,type,version}载入某个组件并获得该组件中的填充单元
        /// </summary>
        /// <param name="articleComponent"></param>
        /// <returns></returns>
        private string[] SelectPopulatedControlUnit(ArticleComponent articleComponent,DataOfUnit dataOfUnit,ArticleKey articleKey)
        {
            List<string> ctrlUnitSet = new List<string>();
            string componentStr = string.Empty;
            if (componentDictionary.TryGetValue(articleComponent, out componentStr))
            {
                Regex rx = new Regex(@"<!--element-(\d*)-->", RegexOptions.Compiled | RegexOptions.IgnoreCase);
                MatchCollection mc = rx.Matches(componentStr);
                //var m = from q in mc.Cast<Match>() select q.Groups[1].Value;
                foreach (Match match in mc)
                {
                    ArticleControlUnit acu = new ArticleControlUnit(match.Groups[1].Value, articleComponent.Type, articleComponent.Version);
                    string controlStr = LoadControlUnit(acu, dataOfUnit,articleKey);
                    
                    //2013-10-29 basilwang 如果是在编辑状态，则返回表单元素
                    if (articleKey.IsEdit)
                    {
                        ctrlUnitSet.Add(controlStr);
                    }
                    else
                    {
                        componentStr = componentStr.Replace(match.Groups[0].Value, controlStr);
                        
                    }
                }
                if (!articleKey.IsEdit)
                {
                    ctrlUnitSet.Add(componentStr);
                }
            }
            return ctrlUnitSet.ToArray();
        }
        /// <summary>
        ///  根据选中的Components得到所有的可填充单元
        /// </summary>
        /// <param name="articleComponents"></param>
        /// <returns></returns>
        private string[] SelectPopulatedControlUnits(IList<ArticleComponent> articleComponents,ArticleKey articleKey,bool needReplace)//发布时调用，修改时也调用
        {
            DataOfUnit dataOfUnit = LoadDataOfUnit(articleKey, needReplace);//fileText.Replace("&nbsp;", " ").Replace("<br/>", "\r\n");修改时应该替换，发布时不应该替换
            List<string> unitList = new List<string>();
            foreach (var articleComponent in articleComponents)
            {
                string[] unitListRange  = SelectPopulatedControlUnit(articleComponent,dataOfUnit,articleKey);
                unitList.AddRange(unitListRange);
            }
            return unitList.ToArray();
        }
        public string SelectHtmlSnippetsOfUnits(ArticleKey articleKey)//修改时调用此方法
        {
            return SelectHtmlSnippetsOfUnits(null,articleKey);
        }
        /// <summary>
        /// 返回相应的表单元素代码片段
        /// </summary>
        /// <param name="articleComponents"></param>
        /// <param name="year"></param>
        /// <param name="month"></param>
        /// <param name="alias"></param>
        /// <returns></returns>
        public string SelectHtmlSnippetsOfUnits(IList<ArticleComponent> articleComponents, ArticleKey articleKey)//articleComponents为null时为修改
        {
            IList<ArticleComponent> articleComponents_handled=new List<ArticleComponent>();
            //2013-11-17 basilwang 如果是修改的时候，则articleComponents为空
            if (articleComponents == null)
            {
                articleComponents_handled=LoadArticleComponent(articleKey);//修改时调用
            }
            else
            {
                bool isDirty = false;
                if (CheckIfArticleTemplateExists(articleKey))
                {
                    articleComponents_handled = LoadArticleComponent(articleKey);
                    //2013-10-23 basilwang 使用了扩展方法比较集合的Hash码
                    if (articleComponents_handled.GetOrderIndependentHashCode() != articleComponents.GetOrderIndependentHashCode())
                    {
                        isDirty = true;
                    }
                }
                else
                {
                    isDirty = true;
                }
                if (isDirty)
                {
                    GenerateForm(articleKey, articleComponents);
                    var t_articleComponents = articlePublishDetailDictionary[articleKey].ArticleComponents;
                    t_articleComponents = articleComponents;
                    /*if (articleDictionary.ContainsKey(articleKey))
                    {
                        articleDictionary[articleKey] = articleComponents;
                    }
                    else
                    {
                        articleDictionary.Add(articleKey, articleComponents);
                    }*/
                    articleComponents_handled = articleComponents;
                }
            }
            string[] populatedControlUnits = SelectPopulatedControlUnits(articleComponents_handled,articleKey,true);//修改或添加时调用，应该为true
            //2013-10-24 basilwang 合并成一个字符串
            return String.Join("", populatedControlUnits);
        }
        /// <summary>
        /// 提交的数据以类DataOfUnit的形式存在，以后缀名json存在
        /// </summary>
        /// <param name="dataOfUnit"></param>
        public void PostDataOfUnit(DataOfUnit dataOfUnit,ArticleKey articleKey)
        {
            string fileName = GetArticleJSONFileName(articleKey);
            var json = JsonConvert.SerializeObject(dataOfUnit);
            using (StreamWriter sw = new StreamWriter(fileName,false))
            {
                sw.Write(json);
            }
            //2013-11-16  basilwang 需要更新缓存
            LoadArticlePublishDetails();
        }
        ///// <summary>
        ///// 返回所有的可填充单元并且返回可填充单元内填写的数据
        ///// </summary>
        ///// <param name="units"></param>
        ///// <returns></returns>
        //public string[] SelectHtmlSnippetsOfUnitsWithPopulatedData(string[] units)
        //{
        //    return null;
        //}
        /// <summary>
        /// 返回包含所有可填充单元和数据的html页面，以后缀名article存在，可以在前台的期刊页面调用（但建议设置代理页面以添加权限
        /// </summary>
        /// <param name="articleComponents"></param>
        public void GenerateHtmlFile(ArticleKey articleKey)//发布时所调用方法
        {
            IList<ArticleComponent> articleComponents = articlePublishDetailDictionary[articleKey].ArticleComponents;
            articleKey.IsEdit = false;
            string fileName = GetArticlePublishFileName(articleKey);
            string[] populatedControlUnits = SelectPopulatedControlUnits(articleComponents, articleKey,false);//发布时为false
            using (StreamWriter sw = new StreamWriter(fileName, false))
            {
                sw.Write(String.Join("", populatedControlUnits));
            }
            //2013-11-14  basilwang 需要更新缓存
            LoadArticlePublishDetails();
        }
        /// <summary>
        /// 生成Form文件
        /// </summary>
        /// <param name="articleComponents"></param>
        private void GenerateForm(ArticleKey articleKey,IList<ArticleComponent> articleComponents)
        {
            XDocument doc = new XDocument(
                // XML declaration
           new XDeclaration("1.0", "uft-8", "yes"),
                // The root element
           new XElement(ns + "Root")
           );
            doc.Root.Add(
                       from p in articleComponents
                       select new XElement(ns + "Component",
                           new XElement(ns+"name", p.Name),
                           new XElement(ns+"type", p.Type),
                           new XElement(ns+"version", p.Version)
                       )

               );
            // Save the XML document to file system
            doc.Save(GetArticleFormFileName(articleKey));
            //2013-11-16  basilwang 需要更新缓存
            LoadArticlePublishDetails();
        }
        /// <summary>
        /// 1) 期刊页面读取组件配置信息并呈现到页面上使用
        /// 2) 读取组件配置信息以便和页面传递的最新的配置信息比较
        /// </summary>
        /// <param name="articleKey"></param>
        /// <returns></returns>
        public IList<ArticleComponent> LoadArticleComponent(ArticleKey articleKey)
        {
            IList<ArticleComponent> list = null;
          

            XDocument doc = XDocument.Load(GetArticleFormFileName(articleKey));
            list = (from p in doc.Root.Elements(ns + "Component")
                            select new ArticleComponent(p.Element(ns + "name").Value,p.Element(ns + "type").Value,p.Element(ns + "version").Value)
                           ).ToList();
               
            return list;
        }
        /// <summary>
        /// 读入json文件的数据到DataOfUnits类中
        /// </summary>
        /// <returns></returns>
        private DataOfUnit LoadDataOfUnit(ArticleKey articleKey,bool needReplace=true)
        {
            DataOfUnit dataOfUnit = new DataOfUnit();
            string fileName = GetArticleJSONFileName(articleKey);
            if (File.Exists(fileName))
            {
                string fileText = FileUtil.GetFileText(fileName);
                if (needReplace)
                {
                    fileText = fileText.Replace("&nbsp;", " ").Replace("<br/>", "\r\n");
                }
                dataOfUnit = (DataOfUnit)JsonConvert.DeserializeObject(fileText, typeof(DataOfUnit));
            }
            return dataOfUnit;
        }
        private string LoadPublishedArticle(ArticleKey articleKey)
        {
            string fileText=string.Empty;
            string fileName = GetArticlePublishFileName(articleKey);
             if (File.Exists(fileName))
             {
                 fileText = FileUtil.GetFileText(fileName);
             }
             return fileText;
        }
        /// <summary>
        /// 得到所有的组件，并按照ArticleComponent的键值存储到字典表里
        /// </summary>
        private void LoadComponents()
        {
            Func<string, ArticleComponent> fun = delegate(string filename)
            {
                var s = filename.Split('.');
                return new ArticleComponent(s[0]+"Choice", s[1], s[2]);
            };
            //2013-10-30 basilwang
            //http://stackoverflow.com/questions/840261/passing-arguments-to-c-sharp-generic-new-of-templated-type
            LoadFileTextToDictionary(articleComponentDirectory, "component", componentDictionary, fun);
        }
        public void LoadArticlePublishDetails()
        {
            Func<string, ArticleKey> fun = delegate(string filename)
            {
                //2013-11-16  basilwang TODO 可能需要处理异常
                var s = filename.Split('.')[0].Split('_');
                return new ArticleKey(int.Parse(s[0]), int.Parse(s[1]), int.Parse(s[2]),s[3]);
            };
            //2013-11-14 basilwang 先清空
            articlePublishDetailDictionary.Clear();
            Dictionary<ArticleKey, string> tArticleDictionary = new Dictionary<ArticleKey, string>();
            LoadFileTextToDictionary(articleTemplateDirectory, "form", tArticleDictionary, fun);
            foreach (var articleKey in tArticleDictionary.Keys)
            {
                var json = LoadDataOfUnit(articleKey);
                var article = LoadPublishedArticle(articleKey);
                var components = LoadArticleComponent(articleKey);
                articlePublishDetailDictionary.Add(articleKey, new ArticlePublishDetail()
                {
                    ArticleKey=articleKey,
                    DataOfUnit = json,
                    ArticleComponents=components,
                    PublishedArticle = article
                });
            }
        }
        /// <summary>
        /// 2013-11-14 basilwang 根据年月（每一期杂志）取得所有的文章
        /// </summary>
        /// <param name="year"></param>
        /// <param name="month"></param>
        /// <returns></returns>
        public IList<ArticlePublishDetail> SelectArticlePublishDetails(int year, int month,int start,int limit,out long total)
        {
            var list = (from p in articlePublishDetailDictionary.Values
                       where p.ArticleKey.Year==year && p.ArticleKey.Month==month
                       orderby p.ArticleKey.Index
                       select p
                         );
            total = list.LongCount();
            return list.Skip(start).Take(limit).ToList<ArticlePublishDetail>();
        }


        public IList<ArticlePublishDetail> SelectArticlePublishDetails(int year, int month)
        {
            var list = (from p in articlePublishDetailDictionary.Values
                        where p.ArticleKey.Year == year && p.ArticleKey.Month == month
                        orderby p.ArticleKey.Index
                        select p
                         );
            return list.ToList<ArticlePublishDetail>();
        }

        public ArticlePublishDetail SelectArticlePublishDetailBy(int year, int month,string alias)
        {
            var article = (from p in articlePublishDetailDictionary.Values
                        where p.ArticleKey.Year == year && p.ArticleKey.Month == month&&p.ArticleKey.Alias==alias
                        select p
                       );
            return article.SingleOrDefault();
        }
        public void DeleteArticle(int year, int month, int index,string alias)
        {
            string formFile = string.Format("{0}_{1}_{2}_{3}.form", year, month, index, alias);
            string jsonFile = string.Format("{0}_{1}_{2}_{3}.json", year, month, index, alias);
            string publishFile = string.Format("{0}_{1}_{2}_{3}.article", year, month, index, alias);
            if (File.Exists(GetArticleTemplateDirectory() + "\\" + formFile))
                File.Delete(GetArticleTemplateDirectory() + "\\" + formFile);

            if (File.Exists(GetArticleTemplateDirectory() + "\\" + jsonFile))
                File.Delete(GetArticleTemplateDirectory() + "\\" + jsonFile);

            if (File.Exists(GetArticlePublishDirectory() + "\\" + publishFile))
                File.Delete(GetArticlePublishDirectory() + "\\" + publishFile);

            LoadArticlePublishDetails();
        }


        private void LoadControlUnits()
        {
            Func<string, ArticleControlUnit> fun = delegate(string filename)
            {
                var s = filename.Split('.');
                return new ArticleControlUnit(s[0], s[1], s[2]);
            };
            LoadFileTextToDictionary(articleControlUnitDirectory, "unit", controlUnitDictionary, fun);

        }
        private void LoadEditableControlUnits()
        {
            Func<string, ArticleControlUnit> fun = delegate(string filename)
            {
                var s = filename.Split('.');
                return new ArticleControlUnit(s[0], s[1], s[2]);
            };
            LoadFileTextToDictionary(articleEditableControlUnitDirectory, "unit", editableControlUnitDictionary, fun);

        }
        private void LoadFileTextToDictionary<T>(string directory, string suffix, Dictionary<T, string> dictionary,Func<string,T> fun) where T : CustomizedKey 
        {
            System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(directory);

            // This method assumes that the application has discovery permissions 
            // for all folders under the specified path.
            IEnumerable<System.IO.FileInfo> fileList = dir.GetFiles(string.Format("*.{0}",suffix), System.IO.SearchOption.TopDirectoryOnly);
            var queryMatchingFiles =
            from file in fileList
            where file.Extension == string.Format(".{0}",suffix)
            let fileText = FileUtil.GetFileText(file.FullName)
            let ac = fun(file.Name)
            select new
            {
                customizedKey = ac,
                fileText = fileText
            };
            foreach (var f in queryMatchingFiles)
            {
                dictionary.Add(f.customizedKey, f.fileText);
            }
        }
        private string LoadControlUnit(ArticleControlUnit articleControlUnit,DataOfUnit dataOfUnit,ArticleKey articleKey)
        {
            string controlUnitsStr = string.Empty;

            if (articleKey.IsEdit)
            {
                controlUnitsStr = LoadEditableControlUnit(articleControlUnit, dataOfUnit, articleKey);
            }
            else
            {
                controlUnitsStr = LoadPrintControlUnit(articleControlUnit, dataOfUnit, articleKey);
            }
            return controlUnitsStr;
        }
        private string LoadPrintControlUnit(ArticleControlUnit articleControlUnit, DataOfUnit dataOfUnit, ArticleKey articleKey)
        {
            /*
          * 2013-10-29 basilwang
          * 标题对应 <!--element-1-->
          * 作者对应 <!--element-2-->
          * 来源对应 <!--element-3-->
          * 文字内容对应<!--element-4-->
          * 图片内容对应<!--element-5-->
          * 相关列表对应<!--element-6-->
          * 步骤列表对应<!--element-7-->
          */
            //string CTRL1 = string.Format("<!--generated by ATF--> <label class=\"control-label\" for=\"title\">标题</label><div class=\"controls\"><input class=\"input-xlarge focused\"  name=\"title\" type=\"text\" placeholder=\"请输入标题\" value=\"{0}\"></div>", dataOfUnit != null ? dataOfUnit.title : string.Empty);
            //string CTRL2 = string.Format("<!--generated by ATF--><label class=\"control-label\" for=\"author\">作者</label><div class=\"controls\"><input class=\"input-xlarge focused\"  name=\"author\" type=\"text\" placeholder=\"请输入作者\" value=\"{0}\"></div>", dataOfUnit != null ? dataOfUnit.author : string.Empty);
            //string CTRL3 = string.Format("<!--generated by ATF--><label class=\"control-label\" for=\"source\">来源</label><div class=\"controls\"><input class=\"input-xlarge focused\"  id=\"source\" type=\"text\" placeholder=\"请输入来源\" value=\"{0}\"></div>", dataOfUnit != null ? dataOfUnit.source : string.Empty);
            //string CTRL4 = string.Format("<!--generated by ATF--><label class=\"control-label\">内容</label><div class=\"controls\"><textarea class=\"span6\" rows=\"10\" name=\"content\"  value=\"{0}\"></textarea></div>", dataOfUnit != null ? dataOfUnit.content : string.Empty);
            //string CTRL5 = string.Format("<!--generated by ATF--><label class=\"control-label\">图片</label><div class=\"controls\"><div class=\"uploader\" id=\"uniform-fileInput\"><input class=\"input-file uniform_on\" id=\"fileInput\" type=\"file\" size=\"19\" style=\"opacity: 0;\"><span class=\"filename\">{0}</span><span class=\"action\">请选择图片</span></div></div>", (dataOfUnit != null && !string.IsNullOrEmpty(dataOfUnit.content_image)) ? dataOfUnit.content_image : "还没有选择图片");
            string ctrl = string.Empty;
            if (controlUnitDictionary.ContainsKey(articleControlUnit))
            {
                ctrl = controlUnitDictionary[articleControlUnit];
            }
            string controlStr = string.Empty;
            switch (articleControlUnit.Name)
            {
                case "1":
                    controlStr = string.Format(ctrl, (dataOfUnit != null && !string.IsNullOrEmpty(dataOfUnit.title)) ? dataOfUnit.title : string.Empty);
                    break;
                case "2":
                    controlStr = string.Format(ctrl, (dataOfUnit != null && !string.IsNullOrEmpty(dataOfUnit.author)) ? dataOfUnit.author : string.Empty);
                    break;
                case "3":
                    controlStr = string.Format(ctrl, (dataOfUnit != null && !string.IsNullOrEmpty(dataOfUnit.source)) ? dataOfUnit.source : string.Empty); ;
                    break;
                case "4":
                    controlStr = string.Format(ctrl, (dataOfUnit != null && !string.IsNullOrEmpty(dataOfUnit.content)) ? dataOfUnit.content : string.Empty); ;
                    break;
                case "5":
                    var isedit = (dataOfUnit != null && !string.IsNullOrEmpty(dataOfUnit.content_image));
                    controlStr = string.Format(ctrl, isedit ? dataOfUnit.content_image : "");
                    break;
                case "6":
                    //controlStr += "<!--generated by ATF-->";
                    if (dataOfUnit != null)
                    {
                        Regex rx = new Regex(@"<!--REPEATTEMPLATE([\w\W\r\n]*?)-->", RegexOptions.Compiled | RegexOptions.IgnoreCase);
                        Match match = rx.Match(ctrl);
                        string repeatContent = string.Empty;
                        for (var i = 0; i < dataOfUnit.related.Count; i++)
                        {
                            var item = dataOfUnit.related[i];
                            repeatContent += string.Format(match.Groups[1].Value, item.related_content, item.related_content_image);

                        }
                        controlStr += rx.Replace(ctrl, repeatContent);
                    }
                    break;
                case "7":
                    //controlStr += "<!--generated by ATF-->";
                    if (dataOfUnit != null)
                    {
                        Regex rx = new Regex(@"<!--REPEATTEMPLATE([\w\W\r\n]*?)-->", RegexOptions.Compiled | RegexOptions.IgnoreCase);
                        Match match = rx.Match(ctrl);
                        string repeatContent = string.Empty;
                        for (var i = 0; i < dataOfUnit.phrase.Count; i++)
                        {
                            var item = dataOfUnit.phrase[i];
                            repeatContent += string.Format(match.Groups[1].Value, item.phrase_content, item.phrase_content_image);

                        }
                        controlStr += rx.Replace(ctrl, repeatContent);
                    }
                    break;

            }
            return controlStr;
        }
        private string LoadEditableControlUnit(ArticleControlUnit articleControlUnit, DataOfUnit dataOfUnit, ArticleKey articleKey)
        {
            /*
           * 2013-10-29 basilwang
           * 标题对应 <!--element-1-->
           * 作者对应 <!--element-2-->
           * 来源对应 <!--element-3-->
           * 文字内容对应<!--element-4-->
           * 图片内容对应<!--element-5-->
           * 相关列表对应<!--element-6-->
           * 步骤列表对应<!--element-7-->
           */
            //string CTRL1 = string.Format("<!--generated by ATF--> <label class=\"control-label\" for=\"title\">标题</label><div class=\"controls\"><input class=\"input-xlarge focused\"  name=\"title\" type=\"text\" placeholder=\"请输入标题\" value=\"{0}\"></div>", dataOfUnit != null ? dataOfUnit.title : string.Empty);
            //string CTRL2 = string.Format("<!--generated by ATF--><label class=\"control-label\" for=\"author\">作者</label><div class=\"controls\"><input class=\"input-xlarge focused\"  name=\"author\" type=\"text\" placeholder=\"请输入作者\" value=\"{0}\"></div>", dataOfUnit != null ? dataOfUnit.author : string.Empty);
            //string CTRL3 = string.Format("<!--generated by ATF--><label class=\"control-label\" for=\"source\">来源</label><div class=\"controls\"><input class=\"input-xlarge focused\"  id=\"source\" type=\"text\" placeholder=\"请输入来源\" value=\"{0}\"></div>", dataOfUnit != null ? dataOfUnit.source : string.Empty);
            //string CTRL4 = string.Format("<!--generated by ATF--><label class=\"control-label\">内容</label><div class=\"controls\"><textarea class=\"span6\" rows=\"10\" name=\"content\"  value=\"{0}\"></textarea></div>", dataOfUnit != null ? dataOfUnit.content : string.Empty);
            //string CTRL5 = string.Format("<!--generated by ATF--><label class=\"control-label\">图片</label><div class=\"controls\"><div class=\"uploader\" id=\"uniform-fileInput\"><input class=\"input-file uniform_on\" id=\"fileInput\" type=\"file\" size=\"19\" style=\"opacity: 0;\"><span class=\"filename\">{0}</span><span class=\"action\">请选择图片</span></div></div>", (dataOfUnit != null && !string.IsNullOrEmpty(dataOfUnit.content_image)) ? dataOfUnit.content_image : "还没有选择图片");
            string ctrl = string.Empty;
            if (editableControlUnitDictionary.ContainsKey(articleControlUnit))
            {
                ctrl = editableControlUnitDictionary[articleControlUnit];
            }
            string controlStr = string.Empty;
            switch (articleControlUnit.Name)
            {
                case "1":
                    controlStr = string.Format(ctrl, (dataOfUnit != null && !string.IsNullOrEmpty(dataOfUnit.title)) ? dataOfUnit.title : string.Empty);
                    break;
                case "2":
                    controlStr = string.Format(ctrl, (dataOfUnit != null && !string.IsNullOrEmpty(dataOfUnit.author)) ? dataOfUnit.author : string.Empty);
                    break;
                case "3":
                    controlStr =  string.Format(ctrl, (dataOfUnit != null && !string.IsNullOrEmpty(dataOfUnit.source)) ? dataOfUnit.source : string.Empty);;
                    break;
                case "4":
                    controlStr =  string.Format(ctrl, (dataOfUnit != null && !string.IsNullOrEmpty(dataOfUnit.content)) ? dataOfUnit.content : string.Empty);;
                    break;
                case "5":
                    var isedit =  (dataOfUnit != null && !string.IsNullOrEmpty(dataOfUnit.content_image)) ;
                    controlStr = string.Format(ctrl, isedit ? dataOfUnit.content_image : "", isedit ? "fileupload-exists" : "fileupload-new");
                    break;
                case "6":
                    //controlStr += "<!--generated by ATF-->";
                    if (dataOfUnit != null)
                    {
                        Regex rx = new Regex(@"<!--REPEATTEMPLATE([\w\W\r\n]*?)-->", RegexOptions.Compiled | RegexOptions.IgnoreCase);
                        Match match = rx.Match(ctrl);
                        string repeatContent = string.Empty;
                        for(var i=0;i<dataOfUnit.related.Count;i++)
                        {
                            var item = dataOfUnit.related[i];
                            repeatContent += string.Format(match.Groups[1].Value, i + 1, item.related_content, item.related_content_image, item.related_content_image!=string.Empty?"fileupload-exists":"fileupload-new");
                                                 
                        }
                        controlStr+=rx.Replace(ctrl, repeatContent);
                    }
                    break;
                case "7":
                    //controlStr += "<!--generated by ATF-->";
                    if (dataOfUnit != null)
                    {
                        Regex rx = new Regex(@"<!--REPEATTEMPLATE([\w\W\r\n]*?)-->", RegexOptions.Compiled | RegexOptions.IgnoreCase);
                        Match match = rx.Match(ctrl);
                        string repeatContent = string.Empty;
                        for (var i = 0; i < dataOfUnit.phrase.Count; i++)
                        {
                            var item = dataOfUnit.phrase[i];
                            repeatContent += string.Format(match.Groups[1].Value, i + 1, item.phrase_content, item.phrase_content_image, item.phrase_content_image != string.Empty ? "fileupload-exists" : "fileupload-new");

                        }
                        controlStr += rx.Replace(ctrl, repeatContent);
                    }
                    break;

            }
            return controlStr;
        }
       //private T GetCustomizedKey<T>(String fileName,Func<string,string,string,T> fun)  where T:CustomizedKey 
       //{
       //    ///TODO 2013-11-14 basilwang 处理异常 防止崩溃
       //    string[] s = fileName.Split('.');
       //    return fun(s[0], s[1], s[2]);

       //}
       private string articlePublishDirectory;
       public string GetArticlePublishDirectory()
       {
           return GetGeneralDirectory(ARTICLE_PUBLISH);
       }
        private string articleComponentDirectory;
        public string GetArticleComponentDirectory()
        {
            return GetGeneralDirectory(ARTICLE_COMPONENT_DIRECTORY);
        }
        private string articleTemplateDirectory;
        public string GetArticleTemplateDirectory()
        {
            return GetGeneralDirectory(ARTICLE_TEMPLATE_DIRECTORY);
        }
        private string articleControlUnitDirectory;
        public string GetArticleControlUnitDirectory()
        {
            return GetGeneralDirectory(ARTICLE_CONTROL_UNIT_DIRECTORY);
        }
        private string articleEditableControlUnitDirectory;
        public string GetArticleEditableControlUnitDirectory()
        {
            return GetGeneralDirectory(ARTICLE_EDITABLE_CONTROL_UNIT_DIRECTORY);
        }
        private string GetGeneralDirectory(string directory)
        {
            string xmlPath;
            if (HttpContext.Current != null)
            {
                xmlPath = HttpContext.Current.Server.MapPath("~/Core/" + directory);
            }
            else
            {
                xmlPath = AppDomain.CurrentDomain.BaseDirectory + "\\" + directory;
            }

            if (!Directory.Exists(xmlPath))
            {
                Directory.CreateDirectory(xmlPath);
                if (!Directory.Exists(xmlPath))
                    throw new DirectoryNotFoundException("Upload文件夹创建失败");
            }

            return xmlPath;
        }
        private bool CheckIfArticleTemplateExists(ArticleKey articleKey)
        {
            string fileName = GetArticleFormFileName(articleKey);
            if (File.Exists(fileName))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        private string GetArticleFormFileName(ArticleKey articleKey)
        {
            return string.Format("{4}\\{0}_{1}_{2}_{3}.form", articleKey.Year, articleKey.Month,articleKey.Index, articleKey.Alias, articleTemplateDirectory);
        }
        private string GetArticleJSONFileName(ArticleKey articleKey)
        {
            return string.Format("{4}\\{0}_{1}_{2}_{3}.json", articleKey.Year, articleKey.Month, articleKey.Index,articleKey.Alias, articleTemplateDirectory);
        }
        private string GetArticlePublishFileName(ArticleKey articleKey)
        {
            return string.Format("{4}\\{0}_{1}_{2}_{3}.article", articleKey.Year, articleKey.Month, articleKey.Index,articleKey.Alias, articlePublishDirectory);
        }
    }
    /// <summary>
    /// 重写ArticleComponent的Hash值，切记不能修改Name,Type和Version
    /// 参见：GetHashCode is implemented but Dictionary is unable to find the key?
    /// http://stackoverflow.com/questions/14079500/gethashcode-is-implemented-but-dictionary-is-unable-to-find-the-key
    ///http://stackoverflow.com/questions/8612973/gethashcode-and-equals-implementation-in-dictionary-c-sharp
    /// </summary>
    /// <returns></returns>
    public class ArticleComponent:CustomizedKey
    {
        public ArticleComponent(string name, string type, string version):base(name,type,version)
        {

        }
        public override int GetHashCode()
        {
            return string.Format("{0}#{1}#{2}", name, type, version).GetHashCode();
        }
        public override bool Equals(object obj)   //When Running this entire code, put a break-point on both the Equals() and GetHashCode() methods, and see the execution flow.
        {
            ArticleComponent other;
            other = (ArticleComponent)obj;
            return (obj.GetHashCode() == other.GetHashCode());

        }
        //public override bool Equals(object obj)
        //{
        //    var articleComponent = obj as ArticleComponent;
        //    return !ReferenceEquals(articleComponent, null) && Equals(articleComponent);
        //}
        //#region IEquatable<ArticleComponent> 成员

        //bool IEquatable<ArticleComponent>.Equals(ArticleComponent other)
        //{
        //    return string.Equals(Name, other.Name, StringComparison.Ordinal) 
        //               && string.Equals(Type, other.Type, StringComparison.Ordinal)
        //               && string.Equals(Version, other.Version, StringComparison.Ordinal);
        //}

        //#endregion
    }
    public class ArticleControlUnit:CustomizedKey
    {
        public ArticleControlUnit(string name, string type, string version)
            : base(name, type, version)
        {

        }
        public override int GetHashCode()
        {
            return string.Format("{0}#{1}#{2}", name, type, version).GetHashCode();
        }
        public override bool Equals(object obj)   //When Running this entire code, put a break-point on both the Equals() and GetHashCode() methods, and see the execution flow.
        {
            ArticleControlUnit other;
            other = (ArticleControlUnit)obj;
            return (obj.GetHashCode() == other.GetHashCode());

        }
    }
    public class DataOfUnit
    {
        public DataOfUnit()
        {
            this.related = new List<RelatedDataOfUnit>();
            this.phrase = new List<PhraseDataOfUnit>();
        }
        public string title
        {
            get;
            set;
        }
        public string author
        {
            get;
            set;
        }
        public string source
        {
            get;
            set;
        }
        public string content
        {
            get;
            set;
        }
        public string content_image
        {
            get;
            set;
        }
        public IList<RelatedDataOfUnit> related
        {
            get;
            set;
        }
        public IList<PhraseDataOfUnit> phrase
        {
            get;
            set;
        }

    }
    public class RelatedDataOfUnit
    {
        public string related_content
        {
            get;
            set;
        }
        public string related_content_image
        {
            get;
            set;
        }
    }
    public class PhraseDataOfUnit
    {
        public string phrase_content
        {
            get;
            set;
        }
        public string phrase_content_image
        {
            get;
            set;
        }
    }
    /// <summary>
    /// 2013-10-30 basilwang 自定义的字典KEY
    /// </summary>
    public abstract class CustomizedKey
    {
        protected string name;
        protected string type;
        protected string version;
        public CustomizedKey()
        {

        }
        public CustomizedKey(string name, string type, string version)
        {
            this.name = name;
            this.type = type;
            this.version = version;
        }
        public string Name
        {
            get { return name; }
        }
        public string Type
        {
            get { return type; }
        }
        public string Version
        {
            get { return version; }
        }
    }
    public class ArticlePublishDetail
    {
        public ArticlePublishDetail()
        {
            this.ArticleComponents = new List<ArticleComponent>();
        }
        public ArticleKey ArticleKey
        {
            get;
            set;
        }
        public string PublishedArticle
        {
            get;
            set;
        }
        public DataOfUnit DataOfUnit
        {
            get;
            set;
        }
        public IList<ArticleComponent> ArticleComponents
        {
            get;
            set;
        }


        public bool isPublished
        {
            get
            {
                return !string.IsNullOrEmpty(PublishedArticle);
            }
        }


    
    }
    public class ArticleKey : CustomizedKey
    {
        private int year;
        private int month;
        private string alias;
        private int index;
        //2013-10-29 basilwang 是否是在编辑状态
        private bool isEdit=true;
        public ArticleKey()
        {

        }
        public ArticleKey(int year, int month,int index,string alias,bool isEdit):this(year,month,index,alias)
        {
            this.isEdit = isEdit;
        }
        public ArticleKey(int year, int month, string alias)
        {
            this.year = year;
            this.month = month;
            this.alias = alias;
        }
        public ArticleKey(int year, int month, int index,string alias)
        {
            this.year = year;
            this.month = month;
            this.alias = alias;
            this.index = index;
        }
        public int Index
        {
            set { index = value; }
            get { return index; }
        }
        public int Year
        {
            set { year = value; }
            get { return year; }
        }
        public int Month
        {
            set { month = value; }
            get { return month; }
        }
        public string Alias
        {
            set { alias = value; }
            get { return alias; }
        }
        public bool IsEdit
        {
            set { isEdit = value; }
            get { return isEdit; }
        }

        public string Id()
        {
            return year.ToString() + month.ToString() + alias;
        }

        public override int GetHashCode()
        {
            return string.Format("{0}#{1}#{2}#{3}", year, month,index, alias).GetHashCode();
        }
        public override bool Equals(object obj)   //When Running this entire code, put a break-point on both the Equals() and GetHashCode() methods, and see the execution flow.
        {
            ArticleKey other;
            other = (ArticleKey)obj;
            return (obj.GetHashCode() == other.GetHashCode());

        }
    }
    public static class ArticleComponentListExtension
    {
        public static int GetOrderIndependentHashCode(this IList<ArticleComponent> source)
        {
            int hash = 0;
            foreach (ArticleComponent element in source)
            {
                hash = hash ^ EqualityComparer<ArticleComponent>.Default.GetHashCode(element);
            }
            return hash;
        }
    }
}
